#include "app.h"
#include "dmu.h"
#include "app_config.h"
#include "ui/ui_ctrl.h"
#include "board.h"
#include "components/lcd_drivers/lcd.h"
#include "components/battery_manager/battery_manager.h"
#include "components/umi/umi_static.h"
#include "components/smcp/smcp.h"
#include "sfud.h"
#include "polsys.h"

#ifdef _APP_ADO_TIME
#define AUTO_DIS_OFF_TIME       (_APP_ADO_TIME/100)     /*自动息屏时间，单位0.1秒*/ 
#else
#define AUTO_DIS_OFF_TIME       100     /*自动息屏时间，单位0.1秒*/ 
#endif

typedef enum _app_st
{
    APP_ST_NORMAL,  // 常规开机，在页面间流转，目前最终会回到主页面
    APP_ST_SLEEP,   // 开机状态下休眠
    APP_ST_POWER_OFF, // 关机未休眠
    APP_ST_POWER_OFF_SLEEP, // 关机已休眠
    APP_ST_POWER_OFF_CHARGE, // 关机充电
}app_st_t;

static polsys_task_t mTask;
static app_st_t mStatus = APP_ST_NORMAL;
static u16 mStatusTime = 0;
static u32 mBaud = 115200;

static void Loop();
static void AppBtnEvent(btn_ev_t e, void *user_data);
static void DisOff();
static void DisOn(ui_page_creat_fun_t creat_fun, void *param);
static void SetStatus(app_st_t st);
static void Smcp_Event(smcp_event_t e);

// 启动事件，程序启动时执行一次
void App_Load()
{
    u8 fpof;    // 首次上电标记，0X55：首次上电
    // sfud_err sf_ret;

    Board_Init();
    Board_LcdPowerOn();

    // sf_ret = sfud_init();
    // while(sf_ret != SFUD_SUCCESS);
    sfud_init();

    Btn_Init();
    SWSD_Init();
    RHC_Init();
    RHC_UpdateRes();
    Smcp_Init();
    Smcp_SetCb(Smcp_Event);
    Lcd_Init(false);
    Ui_Init();
    Polsys_InitTask(&mTask, Loop, 100);

    // 如果产品首次上电，清零一些未初始化的全局变量
    Umi_Read(0x0001, &fpof, 1);
    if(fpof == 0X55)    // 产品首次通电
    {
        fpof = 0;
        Umi_Write(0x0001, &fpof, 1);
        memset((void *)&Dmu_Status, 0, sizeof(dmu_status_t));
        Ui_LoadDefaultPage();
    }
    else if(_Btn_HwIsDown() || _SWSD_IsValid())   // 因为短路导致重启
    {
        Ui_Load(Page_CreatWarn, (void *)UI_WARN_OVER_LOAD);
    }
    else
    {
        Ui_Load(Page_CreatNumMain, NULL);
    }

    Lcd_DispOn();
}

/**
 * 立即清除当前页面并标记关机，稍后休眠，只有5击按键后才能开机
*/
void App_PowerOff()
{
    SetStatus(APP_ST_POWER_OFF);
    DisOff();
    Btn_SetCb(AppBtnEvent, NULL);  // 接管按钮事件
}



/**
 * 清除当前页面并进入低功耗状态，唤醒后显示主页面
*/
void App_Sleep()
{
    if(mStatus == APP_ST_NORMAL)
    {
        SetStatus(APP_ST_SLEEP);
        DisOff();
        Board_Sleep();          // 低功耗
        DisOn(Page_CreatNumMain, NULL);
        SetStatus(APP_ST_NORMAL);
    }
}


// 内部函数

static void Loop()
{
    if(mStatusTime < 65535)mStatusTime++;
    switch(mStatus)
    {
    case APP_ST_NORMAL:
        // 常规开机状态下，超时后休眠或者切换到充电页面，暂由主页面控制
        break;
    case APP_ST_POWER_OFF:
        if(mStatusTime == 5)
        {
            SetStatus(APP_ST_POWER_OFF_SLEEP);
            Board_Sleep();          // 低功耗
            SetStatus(APP_ST_POWER_OFF);
            BM_SetRefreshStatus(true);
        }
        if(Board_GetDcIn()) // 关机状态下充电器接入了
        {
            SetStatus(APP_ST_POWER_OFF_CHARGE);
            DisOn(Page_CreatNumCharge, (void *)1); // 参数1代表关机中，页面将不会接管按钮、咪头事件
            BM_SetRefreshStatus(true);
        }
        break;
    case APP_ST_POWER_OFF_CHARGE:
        if(Board_GetDcIn() == false)    // 关机充电时，充电器拔掉了
        {
            SetStatus(APP_ST_POWER_OFF);
            DisOff();
        }
        break;

    default: break;
    }
}

// 按钮事件，仅在关机后会响应(APP_ST_POWER_OFF\APP_ST_POWER_OFF_CHARGE)
static void AppBtnEvent(btn_ev_t e, void *user_data)
{
    if (mStatus == APP_ST_POWER_OFF || mStatus == APP_ST_POWER_OFF_CHARGE)
    {
        mStatusTime = 0;
        switch(e)
        {
        case BTN_EV_CLICK_5:    // 这里只进行开机操作，关机由UI页面控制
            if(mStatus == APP_ST_POWER_OFF_CHARGE)
            {
                Ui_SwitchToPage(Page_CreatLogo, NULL);
            }
            else
            {   
                DisOn(Page_CreatLogo, NULL);
            }
            SetStatus(APP_ST_NORMAL);
            break;
        default:
            break;
        }
    }
}

/**
 * 清除显示（释放内存），并关闭LCD显示和供电
*/
static void DisOff()
{
    Lcd_DispOff();          // 关显示
    Ui_Clear();             // 清除页面对象
    Board_LcdPowerOff();    // LCD断电
}

/**
 * 开启LCD显示（上电），并立即显示指定页面
*/
static void DisOn(ui_page_creat_fun_t creat_fun, void *param)
{
    Board_LcdPowerOn();         // LCD上电
    Lcd_Init(false);        // 重新初始化LCD
    Ui_SwitchToPage(creat_fun, param);
    Lcd_DispOn();           // 开显示
}

static void SetStatus(app_st_t st)
{
    mStatus = st;
    mStatusTime = 0;
}




// SMCP事件
static void Smcp_Event(smcp_event_t e)
{
    switch(e)
    {
    case SMCP_EV_RECEIVED_PKG:
    {
        const u8 *dat = Smcp_GetReceiveData();
        u16 len = Smcp_GetLength();
        Ui_NotifyEvent(UI_EV_RECEIVED_PKG);
        switch(dat[0])
        {
        case SMCP_CMD_READ:
        {
            smcp_read_t *rd = (smcp_read_t *)dat;
            u8 *buff = malloc(rd->Length + 2);
            if(buff == NULL)
            {
                u8 sbuff[2] = {SMCP_CMD_READ, SMCP_RT_NO_MEM};
                SmcpLink_SendPkg(2, sbuff);
            }
            else
            {
                buff[0] = SMCP_CMD_READ;
                buff[1] = SMCP_RT_SUCCEED;
                Umi_Read(rd->Addr, &buff[2], rd->Length);
                SmcpLink_SendPkg(rd->Length + 2, buff);
                free(buff);
            }
            break;
        }
        case SMCP_CMD_WRITE:
        {
            bool ret;
            u8 buff[2] = {SMCP_CMD_WRITE, SMCP_RT_SUCCEED};
            smcp_write_t *wr = (smcp_write_t *)dat;
            ret = Umi_Write(wr->Addr, wr->Data, len - 4);
            if(!ret)
            {
                buff[1] = SMCP_RT_ST_ERR;
            }
            SmcpLink_SendPkg(2, buff);
            break;
        }
        case SMCP_CMD_LREAD:
        {
            smcp_lread_t *pkg = (smcp_lread_t *)dat;
            u8 *buff = malloc(pkg->Length + 4);
            if(buff == NULL)
            {
                u8 sbuff[2] = {SMCP_CMD_LREAD, SMCP_RT_NO_MEM};
                SmcpLink_SendPkg(2, sbuff);
            }
            else
            {
                buff[0] = SMCP_CMD_LREAD;
                buff[1] = SMCP_RT_SUCCEED;
                sfud_read(sfud_get_device(0), pkg->Addr, pkg->Length, &buff[4]);
                SmcpLink_SendPkg(pkg->Length + 4, buff);
                free(buff);
            }
            break;
        }
        case SMCP_CMD_LWRITE:
        {
            sfud_err ret;
            u8 buff[2] = {SMCP_CMD_LWRITE, SMCP_RT_SUCCEED};
            smcp_lwrite_t *lwr = (smcp_lwrite_t *)dat;
            ret = sfud_write(sfud_get_device(0), lwr->Addr, len - 8, lwr->Data);
            if(ret != SFUD_SUCCESS)
            {
                buff[1] = SMCP_RT_ST_ERR;
            }
            SmcpLink_SendPkg(2, buff);
            break;
        }
        case SMCP_CMD_UPDATE:
            Board_ResetToBl();
            break;
        case SMCP_CMD_ERASE:
        {
            sfud_err ret;
            u8 buff[2] = {SMCP_CMD_ERASE, SMCP_RT_SUCCEED};
            // smcp_erase_t *pkg = (smcp_erase_t *)dat;
            // 直接整片擦除，需要20~60秒时间
            Wdt_Disable();
            ret = sfud_chip_erase(sfud_get_device(0));
            Wdt_Enable();
            if(ret != SFUD_SUCCESS)
            {
                buff[1] = SMCP_RT_ST_ERR;
            }
            else
            {
                Ui_SwitchToPage(Page_CreatWarn, (void *)UI_WARN_UPDATE);  // 切换到更新资源页面
            }
            SmcpLink_SendPkg(2, buff);
            break;
        }
        case SMCP_CMD_SET_BAUD:
        {
            u8 buff[2] = {SMCP_CMD_SET_BAUD, SMCP_RT_SUCCEED};
            smcp_set_baud_t *pkg = (smcp_set_baud_t *)dat;
            Uart1_SetBaud(pkg->Baud);
            SmcpLink_SendPkg(2, buff);
            if(pkg->Act == 0)   // 测试波特率
            {
                Uart1_SetBaud(mBaud);   // 注意：若有缓存，确保数据已经发送完毕
            }
            else        // 设置波特率
            {
                mBaud = pkg->Baud;
            }
            break;
        }
        default: break;
        }
    }
        break;
    default: break;
    }
}







